using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;


public class ObjectPool
{
    #region 单例

    public static ObjectPool _instance;

    public static ObjectPool instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new ObjectPool();
            }
            return _instance;
        }
    }
    private ObjectPool()
    {
        pool = new Dictionary<string, List<GameObject>>();
        prefabs = new Dictionary<string, GameObject>();
    }
    public static ObjectPool GetInstance()
    {
        return instance;
    }

    #endregion


    /// <summary>
    /// 对象池
    /// </summary>
    public Dictionary<string, List<GameObject>> pool;

    /// <summary>
    /// 预设体
    /// </summary>
    private Dictionary<string, GameObject> prefabs;

    /// <summary>
    /// 从对象池中获取对象
    /// </summary>
    /// <param name="objName"></param>
    /// <returns></returns>
    public GameObject GetObj(string objName, string prefab_path = "", object position = null)
    {
        //结果对象
        GameObject result = null;
        //判断是否有该名字的对象池
        if (pool.ContainsKey(objName))
        {
            //对象池里有对象
            if (pool[objName].Count > 0)
            {
                //获取结果
                result = pool[objName][0];
                //激活对象
                result.SetActive(true);
                //从池中移除该对象
                pool[objName].Remove(result);
                //返回结果
                return result;
            }
        }
        //如果没有该名字的对象池或者该名字对象池没有对象

        GameObject prefab = null;
        //如果已经加载过该预设体
        if (prefabs.ContainsKey(objName))
        {
            prefab = prefabs[objName];
        }
        else     //如果没有加载过该预设体
        {
            //加载预设体, 默认`Assets/Resources/Prefabs`
            var _prefab_path = prefab_path != "" ? BdUtils.join(prefab_path, objName) : "Prefabs/" + objName;
            // BdUtils.log(" --- on 加载预设体`prefab_path`:", prefab_path);
            prefab = Resources.Load<GameObject>(_prefab_path);
            BdUtils.assert(prefab, $"*** 未在`Resources`中找到`prefab_path[{_prefab_path}]`对应的obj!");
            //更新字典
            prefabs.Add(objName, prefab);
        }

        //生成

        if (position == null)
            result = UnityEngine.Object.Instantiate(prefab);
        else
        {
            Vector3 _position = BdTools.get_position(position);
            result = UnityEngine.Object.Instantiate(prefab, _position, Quaternion.identity);
        }
        //改名（去除 Clone）
        result.name = objName;
        //返回
        return result;
    }

    public GameObject GetObj(string objName, GameObject prefab, object position = null)
    {
        //结果对象
        GameObject result = null;
        //判断是否有该名字的对象池
        if (pool.ContainsKey(objName))
        {
            //对象池里有对象
            if (pool[objName].Count > 0)
            {
                //获取结果
                result = pool[objName][0];
                //激活对象
                result.SetActive(true);
                //从池中移除该对象
                pool[objName].Remove(result);
                //返回结果
                return result;
            }
        }
        //如果没有该名字的对象池或者该名字对象池没有对象
        //如果已经加载过该预设体
        if (prefabs.ContainsKey(objName))
        {
            prefab = prefabs[objName];
        }
        else     //如果没有加载过该预设体
        {
            // BdUtils.log(" ~~~ on load prefab 加载预设体:", prefab.name);
            //更新字典
            prefabs.Add(objName, prefab);
        }

        //生成
        if (position == null)
            result = UnityEngine.Object.Instantiate(prefab);
        else
        {
            Vector3 _position = BdTools.get_position(position);
            result = UnityEngine.Object.Instantiate(prefab, _position, Quaternion.identity);
        }
        //改名（去除 Clone）
        result.name = objName;
        // result.AddComponent<AutoRecycleToObjectPool>();
        //返回
        return result;
    }

    public void RecycleObj(GameObject obj, float wait_time = 2f)
    {

        float t = wait_time;  // t秒后执行
        DOTween.To(() => t, (x) => t = x, 0, t).OnComplete(
            () =>
            {
                RecycleObj(obj);
            }
        );
    }

    /// <summary>
    /// 回收对象到对象池
    /// </summary>
    /// <param name="objName"></param>
    public void RecycleObj(GameObject obj)
    {
        if (obj == null)
            return;

        //设置为非激活
        obj.SetActive(false);
        //判断是否有该对象的对象池
        if (pool.ContainsKey(obj.name))
        {
            //放置到该对象池
            pool[obj.name].Add(obj);
        }
        else
        {
            //创建该类型的池子，并将对象放入
            pool.Add(obj.name, new List<GameObject>() { obj });
        }

        // /// <summary>
        // /// 3秒后自动回收到对象池
        // /// </summary>
        // /// <returns></returns>
        // IEnumerator AutoRecycle(GameObject obj_i, float time = 3f)
        // {
        //     yield return new WaitForSeconds(time);

        //     RecycleObj(obj_i);
        // }

        // public void auto_recycle(GameObject obj_i, float time = 3f)
        // {
        //     StartCoroutine(AutoRecycle(obj_i, time));
        // }
    }
}